package cn.turboinfo.dongying.api.domain.util;

import cn.turboinfo.dongying.api.entity.common.enumeration.property.PropertyDataType;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ooxml.POIXMLException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * author: sunshow.
 */
@Slf4j
public class TemplateUtils {

    public static final String PLACEHOLDER_INVALID = "-";

    private static final DateTimeFormatter localizedDateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
    // 8/28/1993
    // 1993年8月28日
    private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(""
            + "[M/d/yyyy]"
            + "[yyyy年M月d日]"
    );

    public static final List<DateTimeFormatter> localDateFormatterList = Lists.newArrayList(localizedDateFormatter, dateFormatter);

    private static final DateTimeFormatter internalDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final DateTimeFormatter outputDateFormatter = DateTimeFormatter.ofPattern("yyyy年M月d日");

    private static final DateTimeFormatter owedDateFormatter = DateTimeFormatter.ofPattern("yyyy/M/d");

    private static final DecimalFormat outputDecimalFormatter = new DecimalFormat("#,##0.00");

    /**
     * 对输入字符串进行统一处理
     *
     * @param input    读取到的值
     * @param dataType 数据类型
     * @return 统一处理后的值
     */
    public static String convertInput(String input, PropertyDataType dataType) {
        String value = StringUtils.trim(input);
        switch (dataType) {
            case DATE: {
                if (StringUtils.isBlank(value)) {
                    return null;
                }
                for (DateTimeFormatter formatter : localDateFormatterList) {
                    try {
                        LocalDate localDate = LocalDate.from(formatter.parse(value));
                        // 处理成内部统一格式
                        return internalDateFormatter.format(localDate);
                    } catch (Exception e) {
                    }
                }
                log.error("不支持的日期格式, 不作处理, value={}", value);
                // throw new RuntimeException("不支持的日期格式");
                // 不抛出异常原样输出
                return value;
            }
            case NUMBER: {
                if (StringUtils.isBlank(value)) {
                    return null;
                }
                if (value.endsWith("%")) {
                    // 百分比
                    BigDecimal result = new BigDecimal(StringUtils.substringBeforeLast(value, "%"));
                    return result.multiply(new BigDecimal("0.01")).toString();
                }
                return value;
            }
            case NON_WHITESPACE_STRING: {
                value = StringUtils.deleteWhitespace(value);
                value = StringUtils.replaceChars(value, "　", "");
                return value;
            }
            default:
                return value;
        }
    }

    /**
     * 对输出字符串进行统一处理
     *
     * @param value    读取到的值
     * @param dataType 数据类型
     * @return 统一处理后的值
     */
    public static String convertOutput(String value, PropertyDataType dataType) {
        if (value == null) {
            return "";
        }
        if (StringUtils.isBlank(value)) {
            return value;
        }

        switch (dataType) {
            case DATE: {
                return outputDateFormatter.format(internalDateFormatter.parse(value));
            }
            case NUMBER: {
                return outputDecimalFormatter.format(new BigDecimal(value));
            }
            default:
                return value;
        }
    }

    /**
     * 转换成内部处理的类型
     *
     * @param value    读取到的值
     * @param dataType 数据类型
     * @return 统一处理后的值
     */
    @SuppressWarnings("unchecked")
    public static <T> T convertInternal(String value, PropertyDataType dataType) {
        if (value == null) {
            return null;
        }

        switch (dataType) {
            case DATE: {
                if (StringUtils.isBlank(value)) {
                    return null;
                }
                return (T) LocalDate.from(internalDateFormatter.parse(value));
            }
            case NUMBER: {
                if (StringUtils.isBlank(value)) {
                    return null;
                }
                return (T) (new BigDecimal(value));
            }
            default:
                return (T) value;
        }
    }

    public static String outputInternal(Object value) {
        if (value == null) {
            return "";
        }

        if (value instanceof LocalDate) {
            return outputDateFormatter.format((LocalDate) value);
        }

        if (value instanceof BigDecimal) {
            return outputDecimalFormatter.format(value);
        }

        return String.valueOf(value);
    }


    public static void parseAndReplaceParagraphList(List<XWPFParagraph> paragraphList, Map<String, Object> replacement) throws POIXMLException, IOException, InvalidFormatException {
        //遍历各段落
        if (paragraphList == null) {
            return;
        }

        for (XWPFParagraph paragraph : paragraphList) {
            replaceParagraph(paragraph, replacement);
        }
    }

    public static void replaceParagraph(XWPFParagraph paragraph, Map<String, Object> replacement) throws POIXMLException, IOException, InvalidFormatException {
        String text = paragraph.getText();
        // 不包含模板则不需要处理
        String[] searches = StringUtils.substringsBetween(text, "${", "}");
        if (searches == null || searches.length == 0) {
            return;
        }

        // 逐个替换
        for (String key : searches) {
            String find = "${" + key + "}";
            List<XWPFRun> runs = paragraph.getRuns();
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.getText(0);
                if (StringUtils.isEmpty(runText)) {
                    // 混进了奇怪的东西直接跳过
                    continue;
                }
                boolean found = false;
                // 完整包含 "${" 或者 末尾是 "$" 并且 下一个 run 开头是 "{"
                if (runText.contains("${") ||
                        (runText.endsWith("$") && i < runs.size() - 1 && StringUtils.isNotEmpty(runs.get(i + 1).getText(0)) && runs.get(i + 1).getText(0).startsWith("{"))) {
                    // 从 "$" 开始匹配
                    int start = i; // 第一个包含 find 的 run
                    int end = start;

                    do {
                        if (runText.contains(find)) {
                            found = true;
                            break;
                        }
                        end++;
                        if (end >= runs.size()) {
                            break;
                        }

                        String nextRunText = runs.get(end).getText(0);

                        /*
                        if (nextRunText.contains("${") || (nextRunText.endsWith("$") && end < runs.size() - 1 & runs.get(end + 1).getText(0).startsWith("{"))) {
                            // 出现了新的 中断查找
                            break;
                        }
                        */

                        runText += nextRunText;
                    } while (end - start < 5); // 最多只跨 5 个 run 查找

                    if (found) {
                        // 替换内容
                        // 先直接把内容插到第一个
                        Object o = replacement.get(key);
                        if (Objects.isNull(o)) {
                            continue;
                        }
                        if (o instanceof byte[] is) {
                            // 标签 之前的文案
                            runs.get(start).setText(StringUtils.substringBefore(runs.get(start).getText(0), "$"), 0);
                            // 图片
                            runs.get(start).addPicture(new ByteArrayInputStream(is), XWPFDocument.PICTURE_TYPE_PNG, "test.png", Units.toEMU(100), Units.toEMU(50));
                            // 标签 之后的文案
                            runs.get(start).setText(StringUtils.substringAfter(runs.get(end).getText(0), "}"));

                        } else {
                            StringBuilder newRunText = new StringBuilder();
                            newRunText.append(StringUtils.substringBefore(runs.get(start).getText(0), "$"));
                            newRunText.append(o);
                            // 补上最后一个之后的内容
                            newRunText.append(StringUtils.substringAfter(runs.get(end).getText(0), "}"));
                            // 所有内容都合并到第一个
                            runs.get(start).setText(newRunText.toString(), 0);
                        }

                        // 把其他的置空
                        for (int j = end; j > start; j--) {
                            // 删除 原始的 run 保证变量连续性
                            // 要用 paragraph 删, runs 是个副本
                            paragraph.removeRun(j);
                            // runs.get(j).setText("", 0);
                        }
                    }
                }
                if (found) {
                    break;
                }
            }
        }
    }

    public static void simpleReplaceCellText(XWPFTableCell cell, String text) {
        if (cell.getParagraphs().size() == 0) {
            cell.setText(text);
        } else {
            // 把第一个段落设置对应的文本 并把其他段落删掉
            for (int i = cell.getParagraphs().size() - 1; i > 0; i--) {
                cell.removeParagraph(i);
            }
            XWPFParagraph paragraph = cell.getParagraphs().get(0);
            if (paragraph.getRuns().size() == 0) {
                paragraph.createRun().setText(text);
            } else {
                for (int i = paragraph.getRuns().size() - 1; i > 0; i--) {
                    paragraph.removeRun(i);
                }
                paragraph.getRuns().get(0).setText(text, 0);
            }
        }
    }

    /**
     * insertRow 在word表格中指定位置插入一行，并将某一行的样式复制到新增行
     *
     * @param copyRowIndex 需要复制的行位置
     * @param newRowIndex  需要新增一行的位置
     */
    public static void insertRow(XWPFTable table, int copyRowIndex, int newRowIndex) {
        // 在表格中指定的位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(newRowIndex);
        // 获取需要复制行对象
        XWPFTableRow copyRow = table.getRow(copyRowIndex);
        //复制行对象
        targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());
        //或许需要复制的行的列
        List<XWPFTableCell> copyCells = copyRow.getTableCells();
        //复制列对象
        for (XWPFTableCell copyCell : copyCells) {
            XWPFTableCell targetCell = targetRow.addNewTableCell();
            targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr());
            if (copyCell.getParagraphs() != null && copyCell.getParagraphs().size() > 0) {
                targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr());
                if (copyCell.getParagraphs().get(0).getRuns() != null
                        && copyCell.getParagraphs().get(0).getRuns().size() > 0) {
                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
                    cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold());
                }
            }
        }

    }

    public static void replaceDocxTemplate(XWPFDocument document, Map<String, Object> mappingValueMap) throws IOException, InvalidFormatException {
        // 处理页眉和页脚
        if (document.getHeaderList() != null) {
            for (XWPFHeader header : document.getHeaderList()) {
                TemplateUtils.parseAndReplaceParagraphList(header.getParagraphs(), mappingValueMap);
            }
        }

        if (document.getFooterList() != null) {
            for (XWPFFooter footer : document.getFooterList()) {
                TemplateUtils.parseAndReplaceParagraphList(footer.getParagraphs(), mappingValueMap);
            }
        }

        TemplateUtils.parseAndReplaceParagraphList(document.getParagraphs(), mappingValueMap);

        if (document.getTables() != null) {
            for (XWPFTable table : document.getTables()) {
                // 表格逐个单元格遍历替换
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        TemplateUtils.parseAndReplaceParagraphList(cell.getParagraphs(), mappingValueMap);
                    }
                }
            }
        }
    }

}
